Глава 21

РЕСУРСЫ TURBO VISION

Ресурсы - это индексированные потоки. Главное отличие ресурсов от потоков заключается в том, что к объектам, хранящимся в ресурсе, можно обращаться по ключам - уникальным строкам, идентифицирующим объекты. Таким образом, ресурсы спроектированы специально для облегчения произвольного доступа к потокам.

Использование ресурсов открывает перед Вами ряд интересных возможностей.

Вы можете загружать любые видимые элементы из предварительно созданного файла ресурсов вместо того, чтобы создавать их в теле основной программы. Так как реализация методов Load обычно значительно проще, чем реализация конструкторов Init, это дает возможность несколько уменьшить размер Вашей программы, поскольку в основной программе Вы уже не описываете методы Init, а просто загружаете нужные объекты из ресурса. Разумеется, Вы должны предварительно разработать вспомогательную программу, создающую нужный файл ресурсов.

Разные ресурсы могут хранить одинаковое количество текстовых строк. Поскольку к каждой строке ресурса можно обращаться по индексу, Вы можете простой заменой файла ресурсов изменить, например, язык, на котором написаны сообщения встроенной справочной службы. Причем такая замена никак не отражается на содержательной стороне справок и не влечет за собой никаких изменений в тексте программы. Все, что Вам необходимо в этом случае, - это подготовить несколько идентичных по смыслу, но написанных на разных языках файлов текстовых ресурсов. Для отечественных программистов, ориентирующихся на западный рынок, такая возможность, согласитесь, может показаться весьма заманчивой.

Наконец, смена файла ресурсов позволит Вам легко создать демонстрационную версию Вашей программы без какой-либо ее перенастройки. Для этого Вы готовите два файла ресурсов: один рассчитан на полные возможности программы, другой позволяет использовать только часть ее возможностей и предоставляет пользователю сокращенные меню и строки статуса. Поставка программы с тем или иным файлом ресурсов определяет ее возможности.

В Turbo Vision ресурс реализуется с помощью объекта TResourceFile, который содержит поток и связанную с ним отсортированную коллекцию строк. С помощью метода Init Вы создаете ресурс, методом Put помещаете в поток нужные Вам объекты, а с помощью метода Get получаете из него объект по его имени или индексу.

21.1. СОЗДАНИЕ РЕСУРСА

Поскольку ресурс - это поток, для создания ресурса необходимо открыть (создать) поток. Для этого следует использовать метод Init для потока нужного типа (обычно используется буферизованный поток TBufStream или его потомок). После того как поток успешно открыт, в него помещают нужные объекты с их уникальными ключами и затем поток закрывается - файл ресурсов готов.

Вот как, например, можно создать ресурс, содержащий строку статуса с именем (ключом) «Статус»:

Uses Drivers, Objects, Views, App, Menus; 

var

StatusRes: TResourceFile; {Файл ресурсов}

PStatusStrm: PBufStream; {Буферизованный поток} 

Procedure CreatestatusLine;

{Создает строку статуса и помещает ее в файл ресурсов} 

var

R: TRect;

PStatus: PStatusLine; 

begin

R.Assign(0,24,80,25) ;

PStatus := New(PStatusLine, Init(R,

NewStatusDef(0, $FFFF,

NewStatusKey('~Alt-X~ Выход', kbAltX, cmQuit, 

NewStatusKey('Демонстрация строки статуса',О,0, NIL)),

NIL)) ) ;

StatusRes.Put(PStatus, 'Статус');

Dispose(PStatus, Done) 

end; 

begin

PStatusStrm := New(PBufStream,Init(

'status.res',stCreate,1024));

StatusRes.Init(PStatusStrm); {Создаем поток}

RegisterType(RStatusLine); {Регистрируем строку статуса}

CreateStatusLine; {Помещаем строку статуса в поток}

StatusRes.Done 

end.

В программе создается поток, связанный с указателем PStatusStrm, и в него с помощью процедуры CreateStatusLine помещается строка статуса. Этой строке присваивается ключ Статус.

21.2. ИСПОЛЬЗОВАНИЕ РЕСУРСА

Получить объект из ресурса не представляет проблемы: после инициации файла ресурсов Вы просто используете его метод Get, которому передаете ключ (имя) нужного ресурса. Например, в следующей программе используется файл Status.res, созданный в предыдущем примере:

Uses Objects, Drivers, Views, Menus, Dialogs, App;

var

StatusRes: TResourceFile; {Файл ресурсов}

type

PMyApp =^TМуАрр; {Программа в Turbo Vision}

ТМуАрр = object (TApplication) Constructor Init; 

Procedure InitStatusLine; Virtual;

end;

Constructor TMyApp.Init; 

{Открывает поток, связанный с файлом ресурсов}

begin

StatusRes.Init(New(PBufStream,

Init('status.res',stOpen,1024)));

if StatusRes.StreamA.status <> 0 then 

Halt;

RegisterType(RStatusLine);

Inherited Init 

end;

Procedure TMyApp.initStatusLine; 

{Получает строку статуса из файла ресурсов} 

begin

StatusLine := PStatusLine(StatusRes.Get('Статус')) 

end; 

var

Prog: TMyApp;

begin

Prog.Init; 

Prog.Run; 

Prog.Done 

end.

Заметим, что если в файле ресурсов нет ресурса с указанным именем, метод Get возвращает значение NIL.

Любой ресурс можно получить из файла ресурсов сколько угодно раз и в любом порядке, т.е. файл ресурсов - это поток с произвольным доступом. При необходимости можно дополнять ранее созданный файл ресурсов новыми объектами или заменять существующие в нем объекты другими.

Для ускорения доступа к файлу ресурсов его можно связать с EMS-памятью или использовать для его размещения виртуальный диск.

21.3. СТРОКОВЫЕ РЕСУРСЫ

Списки строк используются в программах Turbo Vision очень часто, поэтому специально для этого вида ресурсов разработаны два особых объекта - TStrListMaker и TStringList. С помощью TSrtListMaker создается строковый ресурс, а с помощью TStringList ранее созданный строковый ресурс становится доступен программе. Предполагается, что создание строкового ресурса и его использование осуществляется в разных программах, поэтому обоим объектам в Turbo Vision присвоен один и тот же регистрационный номер. По той же причине TStrListMaker имеет метод Put, но не имеет метода Get, a TStringList, наоборот, имеет Get и не имеет Put.

В отличие от остальных ресурсов доступ к строковым ресурсам осуществляется по индексам. Таким образом, Ваша программа становится независимой от языка, используемого для вывода сообщений. Чтобы поместить на экран ту или иную информацию, достаточно указать индекс нужного сообщения и в зависимости от используемого файла строкового ресурса сообщение будет выведено на нужном языке.

В двух следующих программах иллюстрируется создание и использование строкового ресурса. В программе CreateStringRes создается строковый ресурс, содержащий все строки текста программы. Константы NStr и SizeStrRes определяют количество строк и общую длину строкового ресурса в байтах. В нашем примере эти величины заранее не известны и выбираются приблизительно, но так, чтобы в ресурсе гарантированно разместился бы весь текст программы. В реальной программе они должны выбираться, исходя из конкретной задачи.

Program CreateStingRes;

{Эта программа создает строковый ресурс}

Uses Objects;

const

SizeStrRes = 2000; {Общая длина всех строк в ресурсе}

NStr = 40; {Общее количество строк} 

var

f: text; {Файл с текстом программы}

ProgText: TResourceFile;

Strings : TStrListMaker; {Строковый ресурс}

k: Integer;

s: String; 

begin

s := copy(ParamStr(0),1,pos('.',ParamStr(0)));

Assign(f,s+'PAS');

Reset(f); {Открываем файл с текстом программы}

RegisterType(RStrListMaker); {Регистрируем объект}

ProgText.Init(New(PBufStream,

InitC prog, res' , stCreate, 1024) )) ;

Strings.Init(SizeStrRes,Nstr);

k := 0;

while not EOF(f) do 

begin

ReadLn(f,s); {Читаем строку программы} 

inc(k) ; {k - порядковый номер строки}

Strings.Put(k,s) {Помещаем строку в ресурс} 

end;

Close (f); {Закрываем файл с текстом программы}

{Помещаем ресурс в поток}

ProgText.Put(@Strings,'Программа');

Strings.Done; {Закрываем ресурс}

ProgText. Done {Закрываем поток} 

end.

В программе UseStringRes текст, полученный из созданного строкового ресурса, читается и выводится на экран «задом наперед», начиная с последней строки текста.

Program UseStingRes;

{Эта программа использует ранее созданный строковый ресурс} 

Uses Objects; 

var

ProgText: TResourceFile; {Файл ресурсов}

PStrings : PStringList; {Строковый ресурс}

k,N: Integer;

begin

RegisterType(RStringList); {Регистрируем объект}

ProgText.Init(New(PBufStream, {Создаем поток}

Init('prog.res',stOpenRead,1024)));

PStrings := {Получаем из потока ресурс}

PStringList(ProgText.Get('Программа'));

N := 1;

while (PStrings^.Get(N))<>'' do

inc(N); {N-1 = общее количество строк} 

for k := N-l downto 1 do

WriteLn(PStrings^.Get(k)); {Получаем и выводим строки} 

PStringsA.Done; {Закрываем ресурс} 

ProgText.Done {Закрываем поток} 

end.

Заметим, что индексы, по которым осуществляется доступ к строковому ресурсу, могут быть произвольными целыми числами в диапазоне от 0 до 65535. Чтобы определить общее количество строк в строковом ресурсе, используется то обстоятельство, что при обращении к TStringList.Get с недействительным индексом метод выдает пустую строку. На практике этот способ нельзя считать надежным (в строковом ресурсе могут храниться и пустые строки), однако других способов определения этого параметра в TStringList не существует.

Перед обращением к TSrtListMaker.Put и TSrtmgList.Get соответствующие объекты должны быть зарегистрированы с помощью RegisterType.